home *** CD-ROM | disk | FTP | other *** search
/ Express Pd: GALORE / Express Pd Galore - The Amiga PD & Shareware CD (1994)(Express Pd)[!][Amiga-CD32-CDTV].iso / productivity / term / termtextbuffer.c < prev    next >
C/C++ Source or Header  |  1993-07-16  |  42KB  |  1,761 lines

  1. /*
  2. **    termTextBuffer.c
  3. **
  4. **    Support routines for the text buffer.
  5. **
  6. **    Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Gadget ID codes. */
  13.  
  14. enum    {    GAD_SCROLLER,GAD_UP,GAD_DOWN };
  15.  
  16.     /* Menu ID codes. */
  17.  
  18. enum    {    MEN_SEARCH,MEN_REPEAT,MEN_GOTO,MEN_CLEARBUF_CONTENTS,MEN_QUITBUF };
  19.  
  20.     /* Gadget ID codes. */
  21.  
  22. enum    {    GAD_STRING,GAD_LOAD,GAD_OK,GAD_CANCEL };
  23.  
  24.     /* A handy macro to determine the length of a string. */
  25.  
  26. #define LINE_WIDTH(s)    (s)[-1]
  27.  
  28.     /* The dimensions of the scroller images. */
  29.  
  30. #define ARROW_WIDTH    18
  31. #define ARROW_HEIGHT    11
  32.  
  33. STATIC struct NewMenu BufferMenu[] =
  34. {
  35.     { NM_TITLE, NULL,         0 , 0, 0, (APTR)0},
  36.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_SEARCH},
  37.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_REPEAT},
  38.     {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  39.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_GOTO},
  40.     {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  41.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_CLEARBUF_CONTENTS},
  42.     {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  43.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_QUITBUF},
  44.  
  45.     { NM_END, 0,             0 , 0, 0, (APTR)0}
  46. };
  47.  
  48.     /* Some private data (render info & window). */
  49.  
  50. STATIC struct Window        *BufferWindow;
  51. STATIC struct Screen        *BufferScreen;
  52.  
  53. STATIC struct RastPort        *BPort;
  54. STATIC APTR             BufferVisualInfo;
  55.  
  56. STATIC LONG             NumBufferLines,
  57.                  NumBufferColumns,
  58.                  LastTopLine;
  59.  
  60. STATIC BYTE             BufferTerminated;
  61.  
  62. STATIC WORD             LocalTextFontWidth,
  63.                  LocalTextFontHeight,
  64.                  LocalTextFontBase;
  65.  
  66. STATIC struct TTextAttr         LocalTextFont;
  67. STATIC UBYTE             LocalTextFontName[MAX_FILENAME_LENGTH];
  68.  
  69. STATIC struct TTextAttr         LocalUserFont;
  70. STATIC UBYTE             LocalUserFontName[MAX_FILENAME_LENGTH];
  71.  
  72. STATIC LONG             TopLine = -1,
  73.                  DisplayedLines;
  74.  
  75. STATIC struct SearchInfo    *BufferSearchInfo;
  76. STATIC BYTE             SearchForward = TRUE;
  77.  
  78. STATIC struct Gadget        *Scroller,
  79.                 *UpArrow,
  80.                 *DownArrow;
  81.  
  82. STATIC struct Image        *UpImage,
  83.                 *DownImage;
  84.  
  85. STATIC UWORD            *BufferLineWidths,
  86.                 *BufferLineOffsets,
  87.                 *BufferColumnOffsets;
  88.  
  89.     /* DeleteScroller(VOID):
  90.      *
  91.      *    Delete scroller and arrow objects.
  92.      */
  93.  
  94. STATIC VOID
  95. DeleteScroller(VOID)
  96. {
  97.     if(Scroller)
  98.     {
  99.         DisposeObject(Scroller);
  100.  
  101.         Scroller = NULL;
  102.     }
  103.  
  104.     if(UpArrow)
  105.     {
  106.         DisposeObject(UpArrow);
  107.  
  108.         UpArrow = NULL;
  109.     }
  110.  
  111.     if(DownArrow)
  112.     {
  113.         DisposeObject(DownArrow);
  114.  
  115.         DownArrow = NULL;
  116.     }
  117.  
  118.     if(UpImage)
  119.     {
  120.         DisposeObject(UpImage);
  121.  
  122.         UpImage = NULL;
  123.     }
  124.  
  125.     if(DownImage)
  126.     {
  127.         DisposeObject(DownImage);
  128.  
  129.         DownImage = NULL;
  130.     }
  131. }
  132.  
  133.     /* CreateScroller(LONG Height):
  134.      *
  135.      *    Create scroller and arrow objects.
  136.      */
  137.  
  138. STATIC BYTE __regargs
  139. CreateScroller(LONG Height)
  140. {
  141.     struct DrawInfo    *DrawInfo;
  142.     BYTE         Result = FALSE;
  143.  
  144.     if(DrawInfo = GetScreenDrawInfo(BufferScreen))
  145.     {
  146.         if(UpImage = (struct Image *)NewObject(NULL,"sysiclass",
  147.             SYSIA_Size,    SYSISIZE_MEDRES,
  148.             SYSIA_Which,    UPIMAGE,
  149.             SYSIA_DrawInfo,    DrawInfo,
  150.         TAG_DONE))
  151.         {
  152.             if(DownImage = (struct Image *)NewObject(NULL,"sysiclass",
  153.                 SYSIA_Size,    SYSISIZE_MEDRES,
  154.                 SYSIA_Which,    DOWNIMAGE,
  155.                 SYSIA_DrawInfo,    DrawInfo,
  156.             TAG_DONE))
  157.             {
  158.                 LONG ScrollerHeight,LeftEdge;
  159.  
  160.                 ScrollerHeight = Height - 2 * ARROW_HEIGHT;
  161.  
  162.                 LeftEdge = BufferScreen -> Width - ARROW_WIDTH;
  163.  
  164.                 if(Scroller = NewObject(NULL,"propgclass",
  165.                     GA_ID,        GAD_SCROLLER,
  166.  
  167.                     GA_Top,        0,
  168.                     GA_Left,    LeftEdge,
  169.                     GA_Width,    ARROW_WIDTH,
  170.                     GA_Height,    ScrollerHeight,
  171.                     GA_Immediate,    TRUE,
  172.                     GA_FollowMouse,    TRUE,
  173.                     GA_RelVerify,    TRUE,
  174.  
  175.                     PGA_Freedom,    FREEVERT,
  176.                     PGA_NewLook,    TRUE,
  177.  
  178.                     PGA_Visible,    1,
  179.                     PGA_Total,    1,
  180.                 TAG_DONE))
  181.                 {
  182.                     STATIC struct TagItem ArrowMappings[] = { GA_ID,GA_ID,TAG_END };
  183.  
  184.                     if(UpArrow = NewObject(NULL,"buttongclass",
  185.                         GA_ID,        GAD_UP,
  186.                         GA_Image,    UpImage,
  187.                         GA_Left,    LeftEdge,
  188.                         GA_Top,        ScrollerHeight,
  189.                         GA_Height,    ARROW_HEIGHT,
  190.                         GA_Width,    ARROW_WIDTH,
  191.                         GA_Immediate,    TRUE,
  192.                         GA_RelVerify,    TRUE,
  193.                         GA_Previous,    Scroller,
  194.  
  195.                         ICA_TARGET,    ICTARGET_IDCMP,
  196.                         ICA_MAP,    ArrowMappings,
  197.                     TAG_DONE))
  198.                     {
  199.                         if(DownArrow = NewObject(NULL,"buttongclass",
  200.                             GA_ID,        GAD_DOWN,
  201.                             GA_Image,    DownImage,
  202.                             GA_Left,    LeftEdge,
  203.                             GA_Top,        ScrollerHeight + ARROW_HEIGHT,
  204.                             GA_Height,    ARROW_HEIGHT,
  205.                             GA_Width,    ARROW_WIDTH,
  206.                             GA_Immediate,    TRUE,
  207.                             GA_RelVerify,    TRUE,
  208.                             GA_Previous,    UpArrow,
  209.  
  210.                             ICA_TARGET,    ICTARGET_IDCMP,
  211.                             ICA_MAP,    ArrowMappings,
  212.                         TAG_DONE))
  213.                             Result = TRUE;
  214.                     }
  215.                 }
  216.             }
  217.         }
  218.  
  219.         FreeScreenDrawInfo(BufferScreen,DrawInfo);
  220.     }
  221.  
  222.     if(!Result)
  223.         DeleteScroller();
  224.  
  225.     return(Result);
  226. }
  227.  
  228.     /* PrintLine(STRPTR Buffer,LONG LineNumber):
  229.      *
  230.      *    Print a line at a given line number in the displayed area.
  231.      */
  232.  
  233. STATIC VOID
  234. PrintLine(STRPTR Buffer,LONG LineNumber)
  235. {
  236.     WORD Length = Buffer[-1];
  237.  
  238.         /* Print the text. */
  239.  
  240.     if(Length)
  241.     {
  242.         Move(BPort,0,BufferLineOffsets[LineNumber] + LocalTextFontBase);
  243.  
  244.         if(Length > NumBufferColumns)
  245.             Length = NumBufferColumns;
  246.  
  247.         Text(BPort,Buffer,Length);
  248.     }
  249.  
  250.         /* The line doesn't exactly fill the displayed line,
  251.          * so erase the remaining columns.
  252.          */
  253.  
  254.     if(Length < BufferLineWidths[LineNumber])
  255.     {
  256.         SetAPen(BPort,0);
  257.         RectFill(BPort,BufferColumnOffsets[Length],BufferLineOffsets[LineNumber],BufferColumnOffsets[BufferLineWidths[LineNumber]] - 1,BufferLineOffsets[LineNumber + 1] - 1);
  258.         SetAPen(BPort,1);
  259.     }
  260.  
  261.     BufferLineWidths[LineNumber] = Length;
  262. }
  263.  
  264.     /* RedrawScreen(LONG FirstLine):
  265.      *
  266.      *    Redraw the contents of the entire screen and return the
  267.      *    number of lines actually drawn.
  268.      */
  269.  
  270. STATIC LONG
  271. RedrawScreen(LONG FirstLine)
  272. {
  273.     LONG i,Last,Line = 0,Result;
  274.  
  275.     ObtainSemaphore(BufferSemaphore);
  276.  
  277.         /* Determine last line to display. */
  278.  
  279.     if((Last = FirstLine + NumBufferLines) >= Lines)
  280.         Last = Lines;
  281.  
  282.     Result = Last - FirstLine;
  283.  
  284.     if(Lines)
  285.     {
  286.         if(LastTopLine != -1)
  287.         {
  288.             LONG Delta = FirstLine - LastTopLine;
  289.  
  290.             if(ABS(Delta) < NumBufferLines)
  291.             {
  292.                     /* No change? */
  293.  
  294.                 if(!Delta)
  295.                 {
  296.                     ReleaseSemaphore(BufferSemaphore);
  297.  
  298.                     return(Result);
  299.                 }
  300.                 else
  301.                 {
  302.                     LastTopLine = FirstLine;
  303.  
  304.                         /* Scrolled up? */
  305.  
  306.                     if(Delta < 0)
  307.                     {
  308.                         for(i = NumBufferLines - 1 ; i >= -Delta ; i--)
  309.                             BufferLineWidths[i] = BufferLineWidths[i + Delta];
  310.  
  311.                         ClipBlit(BPort,0,0,BPort,0,BufferLineOffsets[-Delta],BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines + Delta],MINTERM_COPY);
  312.  
  313.                         Last = FirstLine - Delta;
  314.                     }
  315.                     else
  316.                     {
  317.                         for(i = Delta ; i < NumBufferLines ; i++)
  318.                             BufferLineWidths[i - Delta] = BufferLineWidths[i];
  319.  
  320.                             /* Scrolled down. */
  321.  
  322.                         ClipBlit(BPort,0,BufferLineOffsets[Delta],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - Delta],MINTERM_COPY);
  323.  
  324.                         FirstLine += NumBufferLines - Delta;
  325.  
  326.                         Line = NumBufferLines - Delta;
  327.                     }
  328.                 }
  329.             }
  330.             else
  331.                 LastTopLine = FirstLine;
  332.         }
  333.         else
  334.             LastTopLine = FirstLine;
  335.  
  336.         if(BufferLines)
  337.         {
  338.             for(i = FirstLine ; i < Last ; i++)
  339.                 PrintLine(BufferLines[i],Line++);
  340.         }
  341.     }
  342.  
  343.     ReleaseSemaphore(BufferSemaphore);
  344.  
  345.         /* We didn't fill the whole screen, so clear the rest. */
  346.  
  347.     if(Result < NumBufferLines)
  348.     {
  349.         WORD i;
  350.  
  351.         for(i = Result ; i < NumBufferLines ; i++)
  352.             BufferLineWidths[i] = 0;
  353.  
  354.         SetAPen(BPort,0);
  355.         RectFill(BPort,0,BufferLineOffsets[Result],BufferColumnOffsets[NumBufferColumns] - 1,BufferLineOffsets[NumBufferLines] - 1);
  356.         SetAPen(BPort,1);
  357.     }
  358.  
  359.     return(Result);
  360. }
  361.  
  362.     /* MarkArea(LONG Column,LONG Line,LONG Length):
  363.      *
  364.      *    Mark an area in the term Buffer window.
  365.      */
  366.  
  367. STATIC VOID
  368. MarkArea(LONG Column,LONG Line,LONG Length)
  369. {
  370.     STATIC LONG OldColumn = -1,OldLine = -1,OldLength = -1;
  371.  
  372.     if(OldColumn != -1)
  373.         ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[OldColumn],BufferLineOffsets[OldLine],BufferColumnOffsets[OldLength],LocalTextFontHeight,MINTERM_NOT_C);
  374.  
  375.     if(Column != -1)
  376.     {
  377.         if(OldColumn != Column || OldLine != Line || OldLength != Length)
  378.             ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[Column],BufferLineOffsets[Line],BufferColumnOffsets[Length],LocalTextFontHeight,MINTERM_NOT_C);
  379.     }
  380.  
  381.     OldColumn    = Column;
  382.     OldLine        = Line;
  383.     OldLength    = Length;
  384. }
  385.  
  386.     /* BufferClipPage(struct BlockMarker *Marker):
  387.      *
  388.      *    Send the marked area to the clipboard.
  389.      */
  390.  
  391. STATIC VOID __inline
  392. BufferClipPage(struct BlockMarker *Marker)
  393. {
  394.     if(BufferLines)
  395.     {
  396.         struct IFFHandle *Handle;
  397.  
  398.         if(Handle = AllocIFF())
  399.         {
  400.             if(Handle -> iff_Stream = (ULONG)OpenClipboard(Config -> ClipConfig -> ClipboardUnit))
  401.             {
  402.                 InitIFFasClip(Handle);
  403.  
  404.                 if(!OpenIFF(Handle,IFFF_WRITE))
  405.                 {
  406.                     if(!PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN))
  407.                     {
  408.                         if(!PushChunk(Handle,0,ID_CHRS,IFFSIZE_UNKNOWN))
  409.                         {
  410.                             LONG    Lines = Marker -> LastLine - Marker -> FirstLine - 1,
  411.                                 i;
  412.  
  413.                             if(LINE_WIDTH(BufferLines[Marker -> FirstLine]) > Marker -> FirstColumn)
  414.                                 WriteTrimmedString(Handle,&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],LINE_WIDTH(BufferLines[Marker -> FirstLine]) - Marker -> FirstColumn);
  415.  
  416.                             WriteChunkBytes(Handle,"\n",1);
  417.  
  418.                             if(Lines > 0)
  419.                             {
  420.                                 for(i = 0 ; i < Lines ; i++)
  421.                                 {
  422.                                     if(LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]))
  423.                                         WriteTrimmedString(Handle,BufferLines[Marker -> FirstLine + 1 + i],LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]));
  424.  
  425.                                     WriteChunkBytes(Handle,"\n",1);
  426.                                 }
  427.                             }
  428.  
  429.                             if(Marker -> LastColumn > LINE_WIDTH(BufferLines[Marker -> LastLine]))
  430.                                 WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],LINE_WIDTH(BufferLines[Marker -> LastLine]));
  431.                             else
  432.                                 WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],Marker -> LastColumn);
  433.  
  434.                             WriteChunkBytes(Handle,"\n",1);
  435.  
  436.                             PopChunk(Handle);
  437.                         }
  438.  
  439.                         PopChunk(Handle);
  440.                     }
  441.  
  442.                     CloseIFF(Handle);
  443.                 }
  444.  
  445.                 CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
  446.             }
  447.  
  448.             FreeIFF(Handle);
  449.         }
  450.     }
  451. }
  452.  
  453.     /* BufferClip(VOID):
  454.      *
  455.      *    Start buffer marking process.
  456.      */
  457.  
  458. STATIC VOID
  459. BufferClip(VOID)
  460. {
  461.     struct BlockMarker    *Marker;
  462.     LONG             FirstX = BufferWindow -> MouseX / LocalTextFontWidth,
  463.                  FirstY = BufferWindow -> MouseY / LocalTextFontHeight;
  464.  
  465.     if(Marker = BM_SetMark(BufferWindow -> RPort,ToggleSelect,ToggleSelect,NumBufferColumns,NumBufferLines,0,0,TopLine,Lines,BufferWindow -> MouseX / LocalTextFontWidth,BufferWindow -> MouseY / LocalTextFontHeight,LocalTextFontWidth,LocalTextFontHeight))
  466.     {
  467.         struct IntuiMessage    *Massage;
  468.         ULONG             Code,IClass;
  469.         BYTE             Done = FALSE,Aborted = FALSE;
  470.         LONG             PlusX = LocalTextFontWidth - 1,
  471.                      MouseX,MouseY,
  472.                      Delta = 0;
  473.  
  474.         ReportMouse(TRUE,BufferWindow);
  475.  
  476.         while(!Done)
  477.         {
  478.             WaitPort(BufferWindow -> UserPort);
  479.  
  480.             while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
  481.             {
  482.                 IClass    = Massage -> Class;
  483.                 Code    = Massage -> Code;
  484.                 MouseX    = Massage -> MouseX;
  485.                 MouseY    = Massage -> MouseY;
  486.  
  487.                 ReplyMsg(Massage);
  488.  
  489.                 if(IClass == IDCMP_INACTIVEWINDOW)
  490.                 {
  491.                     Done = Aborted = TRUE;
  492.  
  493.                     break;
  494.                 }
  495.  
  496.                 if(IClass == IDCMP_INTUITICKS && Delta != 0)
  497.                 {
  498.                     if(BufferLines)
  499.                     {
  500.                         if((Delta > 0 && TopLine + NumBufferLines < Lines) || (Delta < 0 && TopLine > 0))
  501.                         {
  502.                             if(Delta < 0)
  503.                             {
  504.                                 WORD i;
  505.  
  506.                                 for(i = NumBufferLines - 1 ; i > -Delta ; i--)
  507.                                     BufferLineWidths[i] = BufferLineWidths[i + Delta];
  508.  
  509.                                 if(DisplayedLines)
  510.                                     ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  511.  
  512.                                 BufferLineWidths[0] = NumBufferColumns;
  513.  
  514.                                 PrintLine(BufferLines[--TopLine],0);
  515.                             }
  516.                             else
  517.                             {
  518.                                 WORD i;
  519.  
  520.                                 for(i = Delta ; i < NumBufferLines ; i++)
  521.                                     BufferLineWidths[i - Delta] = BufferLineWidths[i];
  522.  
  523.                                 if(DisplayedLines)
  524.                                     ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  525.  
  526.                                 BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;
  527.  
  528.                                 PrintLine(BufferLines[TopLine + NumBufferLines],NumBufferLines - 1);
  529.  
  530.                                 TopLine++;
  531.                             }
  532.  
  533.                             Marker -> Top += Delta;
  534.                             Marker -> LastY -= Delta;
  535.  
  536.                             BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
  537.                         }
  538.                         else
  539.                             Delta = 0;
  540.                     }
  541.                 }
  542.  
  543.                 if(IClass == IDCMP_MOUSEBUTTONS && (Code & IECODE_UP_PREFIX))
  544.                 {
  545.                     BM_Draw(Marker,Marker -> Unselect);
  546.  
  547.                     Done = TRUE;
  548.  
  549.                     break;
  550.                 }
  551.  
  552.                 if(IClass == IDCMP_MOUSEMOVE)
  553.                 {
  554.                     BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,0);
  555.  
  556.                     if(MouseY < 1)
  557.                     {
  558.                         if(TopLine > 0)
  559.                             Delta = -1;
  560.                     }
  561.                     else
  562.                     {
  563.                         if(MouseY >= BufferWindow -> Height - 1 && TopLine + NumBufferLines < Lines)
  564.                             Delta = 1;
  565.                     }
  566.  
  567.                     while(Delta)
  568.                     {
  569.                         MouseX    = Window -> MouseX;
  570.                         MouseY    = Window -> MouseY;
  571.  
  572.                         if((Delta < 0 && MouseY > 0) || (Delta > 0 && MouseY < BufferWindow -> Height - 1))
  573.                             break;
  574.                         else
  575.                         {
  576.                             if(BufferLines)
  577.                             {
  578.                                 if((Delta > 0 && TopLine + NumBufferLines < Lines) || (Delta < 0 && TopLine > 0))
  579.                                 {
  580.                                     if(Delta < 0)
  581.                                     {
  582.                                         WORD i;
  583.  
  584.                                         for(i = NumBufferLines - 1 ; i > -Delta ; i--)
  585.                                             BufferLineWidths[i] = BufferLineWidths[i + Delta];
  586.  
  587.                                         if(DisplayedLines)
  588.                                             ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  589.  
  590.                                         BufferLineWidths[0] = NumBufferColumns;
  591.  
  592.                                         PrintLine(BufferLines[--TopLine],0);
  593.                                     }
  594.                                     else
  595.                                     {
  596.                                         WORD i;
  597.  
  598.                                         for(i = Delta ; i < NumBufferLines ; i++)
  599.                                             BufferLineWidths[i - Delta] = BufferLineWidths[i];
  600.  
  601.                                         if(DisplayedLines)
  602.                                             ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  603.  
  604.                                         BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;
  605.  
  606.                                         PrintLine(BufferLines[TopLine + NumBufferLines],NumBufferLines - 1);
  607.  
  608.                                         TopLine++;
  609.                                     }
  610.  
  611.                                     Marker -> Top    += Delta;
  612.                                     Marker -> LastY    -= Delta;
  613.  
  614.                                     BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
  615.  
  616.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  617.                                         PGA_Top,TopLine,
  618.                                     TAG_DONE);
  619.                                 }
  620.                                 else
  621.                                     break;
  622.                             }
  623.                             else
  624.                                 break;
  625.                         }
  626.                     }
  627.  
  628.                     Delta = 0;
  629.                 }
  630.             }
  631.         }
  632.  
  633.         ReportMouse(FALSE,BufferWindow);
  634.  
  635.         while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
  636.             ReplyMsg(Massage);
  637.  
  638.         if(!Aborted)
  639.         {
  640.             if(FirstX != BufferWindow -> MouseX / LocalTextFontWidth || FirstY != BufferWindow -> MouseY / LocalTextFontHeight)
  641.             {
  642.                 SetWait(BufferWindow);
  643.  
  644.                 if(Marker -> FirstColumn == Marker -> Width)
  645.                 {
  646.                     Marker -> FirstLine++;
  647.  
  648.                     Marker -> FirstColumn = 0;
  649.                 }
  650.  
  651.                 if(Marker -> LastColumn == 0)
  652.                 {
  653.                     Marker -> LastLine--;
  654.  
  655.                     Marker -> LastColumn = Marker -> Width;
  656.                 }
  657.  
  658.                 if(Marker -> FirstLine <= Marker -> LastLine)
  659.                 {
  660.                     if(Marker -> FirstLine != Marker -> LastLine || Marker -> FirstColumn != Marker -> LastColumn)
  661.                     {
  662.                         if(BufferLines)
  663.                         {
  664.                             if(Marker -> FirstLine == Marker -> LastLine)
  665.                                 SaveClip(&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],Marker -> LastColumn - Marker -> FirstColumn);
  666.                             else
  667.                                 BufferClipPage(Marker);
  668.                         }
  669.                     }
  670.                 }
  671.  
  672.                 ClrWait(BufferWindow);
  673.             }
  674.         }
  675.  
  676.         FreeVec(Marker);
  677.     }
  678. }
  679.  
  680.     /* StartBufferSearch(BYTE NewSearchString):
  681.      *
  682.      *    Search the buffer for a string.
  683.      */
  684.  
  685. STATIC VOID
  686. StartBufferSearch(BYTE NewSearchString)
  687. {
  688.     BlockWindow(BufferWindow);
  689.  
  690.     if(Lines)
  691.     {
  692.         STATIC UBYTE SearchBuffer[256];
  693.  
  694.         BYTE StartSearch = TRUE;
  695.  
  696.         if(NewSearchString || !SearchBuffer[0])
  697.         {
  698.             if(GetSearchString(BufferWindow,&BufferTerminated,SearchBuffer,&SearchForward))
  699.             {
  700.                 if(SearchBuffer[0])
  701.                 {
  702.                     if(BufferSearchInfo)
  703.                         DeleteSearchInfo(BufferSearchInfo);
  704.  
  705.                     BufferSearchInfo = CreateSearchInfo(SearchBuffer,SearchForward);
  706.                 }
  707.                 else
  708.                     StartSearch = FALSE;
  709.             }
  710.             else
  711.                 StartSearch = FALSE;
  712.         }
  713.         else
  714.         {
  715.             if(!BufferSearchInfo)
  716.                 BufferSearchInfo = CreateSearchInfo(SearchBuffer,TRUE);
  717.         }
  718.  
  719.         if(StartSearch && BufferSearchInfo)
  720.         {
  721.             LONG LineNumber;
  722.  
  723.             ObtainSemaphore(BufferSemaphore);
  724.  
  725.             LineNumber = SearchTextBuffer(BufferSearchInfo);
  726.  
  727.             ReleaseSemaphore(BufferSemaphore);
  728.  
  729.             if(LineNumber == -1)
  730.             {
  731.                 BlockWindows();
  732.  
  733.                 MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_DID_NOT_FIND_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SearchBuffer);
  734.  
  735.                 ReleaseWindows();
  736.  
  737.                 FlushMsg(BufferWindow);
  738.  
  739.                 BufferSearchInfo -> FoundY = -1;
  740.  
  741.                 MarkArea(-1,-1,-1);
  742.             }
  743.             else
  744.             {
  745.                 if(LineNumber < TopLine)
  746.                 {
  747.                     MarkArea(-1,-1,-1);
  748.  
  749.                     DisplayedLines = RedrawScreen(TopLine = LineNumber);
  750.  
  751.                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  752.                         PGA_Top,TopLine,
  753.                     TAG_DONE);
  754.                 }
  755.                 else
  756.                 {
  757.                     if(LineNumber > TopLine + DisplayedLines - 1)
  758.                     {
  759.                         MarkArea(-1,-1,-1);
  760.  
  761.                         if(LineNumber >= Lines - NumBufferLines)
  762.                         {
  763.                             LONG NewCurrentLine;
  764.  
  765.                             if((NewCurrentLine = Lines - NumBufferLines) < 0)
  766.                                 NewCurrentLine = 0;
  767.  
  768.                             if(TopLine != NewCurrentLine)
  769.                                 DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  770.                         }
  771.                         else
  772.                             DisplayedLines = RedrawScreen(TopLine = LineNumber);
  773.  
  774.                         SetGadgetAttrs(Scroller,BufferWindow,NULL,
  775.                             PGA_Top,TopLine,
  776.                         TAG_DONE);
  777.                     }
  778.                 }
  779.  
  780.                 MarkArea(BufferSearchInfo -> FoundX,LineNumber - TopLine,BufferSearchInfo -> PatternWidth);
  781.             }
  782.         }
  783.     }
  784.     else
  785.         MyEasyRequest(BufferWindow,LocaleString(MSG_GLOBAL_NOTHING_IN_THE_BUFFER_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
  786.  
  787.     ReleaseWindow(BufferWindow);
  788. }
  789.  
  790.     /* LaunchBuffer():
  791.      *
  792.      *    Launch the buffer process.
  793.      */
  794.  
  795. BYTE
  796. LaunchBuffer()
  797. {
  798.         /* Is the buffer process already running? */
  799.  
  800.     if(BufferProcess)
  801.     {
  802.             /* Tell it to bring its screen to the front. */
  803.  
  804.         Signal(BufferProcess,SIG_TOFRONT);
  805.  
  806.             /* Return success. */
  807.  
  808.         return(TRUE);
  809.     }
  810.     else
  811.     {
  812.         struct MsgPort    *ReplyPort;
  813.         BYTE         Result = FALSE;
  814.  
  815.             /* Create reply port. */
  816.  
  817.         if(ReplyPort = CreateMsgPort())
  818.         {
  819.             struct Message *Message;
  820.  
  821.                 /* Create startup message. */
  822.  
  823.             if(Message = (struct Message *)AllocVec(sizeof(struct Message),MEMF_ANY|MEMF_CLEAR))
  824.             {
  825.                 Message -> mn_ReplyPort    = ReplyPort;
  826.                 Message -> mn_Length    = sizeof(struct Message);
  827.  
  828.                     /* Launc the buffer process. */
  829.  
  830.                 if(BufferProcess = (struct Process *)CreateNewProcTags(
  831.                     NP_Entry,    BufferServer,
  832.                     NP_Name,    "term buffer process",
  833.                     NP_Priority,    0,
  834.                     NP_StackSize,    8192,
  835.                     NP_WindowPtr,    -1,
  836.                 TAG_END))
  837.                 {
  838.                         /* Send the startup message. */
  839.  
  840.                     PutMsg(&BufferProcess -> pr_MsgPort,Message);
  841.  
  842.                         /* Wait for reply. */
  843.  
  844.                     WaitPort(ReplyPort);
  845.  
  846.                         /* Pick up the reply. */
  847.  
  848.                     GetMsg(ReplyPort);
  849.  
  850.                         /* Is the process still running? */
  851.  
  852.                     if(BufferProcess)
  853.                         Result = TRUE;
  854.                 }
  855.  
  856.                     /* Free the startup message. */
  857.  
  858.                 FreeVec(Message);
  859.             }
  860.  
  861.                 /* Delete the reply port. */
  862.  
  863.             DeleteMsgPort(ReplyPort);
  864.         }
  865.  
  866.             /* Return the result. */
  867.  
  868.         return(Result);
  869.     }
  870. }
  871.  
  872.     /* TerminateBuffer():
  873.      *
  874.      *    Terminate the buffer process.
  875.      */
  876.  
  877. VOID
  878. TerminateBuffer()
  879. {
  880.     if(BufferProcess)
  881.     {
  882.         Forbid();
  883.  
  884.         Signal(BufferProcess,SIG_KILL);
  885.  
  886.         ClrSignal(SIG_HANDSHAKE);
  887.  
  888.         Wait(SIG_HANDSHAKE);
  889.  
  890.         Permit();
  891.     }
  892.  
  893.     LastTopLine = -1;
  894. }
  895.  
  896.     /* BufferServer():
  897.      *
  898.      *    Asynchronous task to display the data stored in the
  899.      *    scrollback display buffer.
  900.      */
  901.  
  902. VOID __saveds
  903. BufferServer()
  904. {
  905.     struct ColorSpec     ColorSpec[3];
  906.  
  907.     ULONG             SignalSet;
  908.  
  909.     struct IntuiMessage    *Massage;
  910.     ULONG             IClass,Code,Qualifier,LastQualifier = NULL;
  911.     UBYTE             Char,LastChar = 0;
  912.  
  913.     LONG             MouseX,MouseY,LastWidth = 0;
  914.  
  915.     UBYTE             PercentBuffer[80];
  916.  
  917.     struct Menu        *BufferMenuStrip;
  918.  
  919.     LONG             Width;
  920.     ULONG             DisplayMode;
  921.  
  922.     struct Rectangle     DisplayClip;
  923.     struct DimensionInfo     DimensionInfo;
  924.  
  925.     UWORD             SomeColour,Height;
  926.  
  927.     struct TextFont        *LocalFont;
  928.  
  929.     struct Message        *StartupMessage;
  930.     struct MsgPort        *StartupPort = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
  931.     struct TagItem        *TagList;
  932.  
  933.         /* Wait for startup message. */
  934.  
  935.     WaitPort(StartupPort);
  936.  
  937.     StartupMessage = GetMsg(StartupPort);
  938.  
  939.         /* Clone the global font data. */
  940.  
  941.     LocalTextFontWidth    = TextFontWidth;
  942.     LocalTextFontHeight    = TextFontHeight;
  943.     LocalTextFontBase    = TextFontBase;
  944.  
  945.     memcpy(&LocalTextFont,&TextAttr,sizeof(struct TTextAttr));
  946.  
  947.     LocalTextFont . tta_Name = LocalTextFontName;
  948.  
  949.     strcpy(LocalTextFontName,TextAttr . tta_Name);
  950.  
  951.     memcpy(&LocalUserFont,&UserFont,sizeof(struct TTextAttr));
  952.  
  953.     LocalUserFont . tta_Name = LocalUserFontName;
  954.  
  955.     strcpy(LocalUserFontName,UserFont . tta_Name);
  956.  
  957.         /* Reset top line index. */
  958.  
  959.     LastTopLine = -1;
  960.  
  961.         /* Up and running... */
  962.  
  963.     BufferTerminated = FALSE;
  964.  
  965.         /* Set up the startup colours for our buffer screen. */
  966.  
  967.     ColorSpec[0] . ColorIndex    = 0;
  968.     ColorSpec[0] . Red        = (Config -> ScreenConfig -> Colours[0] >> 8) & 0xF;
  969.     ColorSpec[0] . Green        = (Config -> ScreenConfig -> Colours[0] >> 4) & 0xF;
  970.     ColorSpec[0] . Blue        = (Config -> ScreenConfig -> Colours[0]     ) & 0xF;
  971.  
  972.     switch(Config -> ScreenConfig -> ColourMode)
  973.     {
  974.         case COLOUR_EIGHT:
  975.  
  976.             SomeColour = Config -> ScreenConfig -> Colours[7];
  977.             break;
  978.  
  979.         case COLOUR_SIXTEEN:
  980.  
  981.             SomeColour = Config -> ScreenConfig -> Colours[15];
  982.             break;
  983.  
  984.         case COLOUR_AMIGA:
  985.         case COLOUR_MONO:
  986.  
  987.             SomeColour = Config -> ScreenConfig -> Colours[1];
  988.             break;
  989.     }
  990.  
  991.     ColorSpec[1] . ColorIndex    = 1;
  992.     ColorSpec[1] . Red        = (SomeColour >> 8) & 0xF;
  993.     ColorSpec[1] . Green        = (SomeColour >> 4) & 0xF;
  994.     ColorSpec[1] . Blue        = (SomeColour     ) & 0xF;
  995.  
  996.     ColorSpec[2] . ColorIndex    = -1;
  997.  
  998.         /* We'll use a fixed screen width, only the
  999.          * height is adapted from the main screen.
  1000.          */
  1001.  
  1002.     DisplayMode = Config -> ScreenConfig -> DisplayMode;
  1003.  
  1004.         /* Set up the actual width of the screen we want. */
  1005.  
  1006.     Width = Config -> CaptureConfig -> BufferWidth * LocalTextFontWidth + ARROW_WIDTH + 1;
  1007.  
  1008.         /* Get the mode dimension info. */
  1009.  
  1010.     if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,DisplayMode))
  1011.     {
  1012.             /* Determine maximum text overscan width. */
  1013.  
  1014.         LONG TextWidth = DimensionInfo . TxtOScan . MaxX - DimensionInfo . TxtOScan . MinX + 1;
  1015.  
  1016.             /* Too small? */
  1017.  
  1018.         if(Width < DimensionInfo . MinRasterWidth)
  1019.             Width = DimensionInfo . MinRasterWidth;
  1020.  
  1021.             /* Far too large? */
  1022.  
  1023.         if(Width > DimensionInfo . MaxRasterWidth)
  1024.             Width = DimensionInfo . MaxRasterWidth;
  1025.  
  1026.             /* A bit too large? */
  1027.  
  1028.         if(Width > TextWidth)
  1029.             Width = TextWidth;
  1030.  
  1031.         if(LocalFont = OpenFont(&LocalTextFont))
  1032.         {
  1033.                 /* Inquire the text overscan dimensions. */
  1034.  
  1035.             if(QueryOverscan(DisplayMode,&DisplayClip,OSCAN_TEXT))
  1036.             {
  1037.                     /* Centre the buffer screen. */
  1038.  
  1039.                 if(DisplayClip . MaxX - DisplayClip . MinX + 1 > Width)
  1040.                 {
  1041.                     LONG Differ = (DisplayClip . MaxX - DisplayClip . MinX + 1 - Width) / 2;
  1042.  
  1043.                     switch(Config -> CaptureConfig -> BufferScreenPosition)
  1044.                     {
  1045.                         case SCREEN_LEFT:
  1046.  
  1047.                             DisplayClip . MaxX = DisplayClip . MinX + Width;
  1048.                             break;
  1049.  
  1050.                         case SCREEN_RIGHT:
  1051.  
  1052.                             DisplayClip . MinX = DisplayClip . MaxX - Width;
  1053.                             break;
  1054.  
  1055.                         case SCREEN_CENTRE:
  1056.  
  1057.                             DisplayClip . MinX += Differ;
  1058.                             DisplayClip . MaxX -= Differ;
  1059.  
  1060.                             break;
  1061.                     }
  1062.                 }
  1063.  
  1064.                     /* Open a single bitplane clone of the main screen. */
  1065.  
  1066.                 if(BufferScreen = (struct Screen *)OpenScreenTags(NULL,
  1067.                     SA_Title,    LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),
  1068.                     SA_Depth,    1,
  1069.                     SA_DClip,    &DisplayClip,
  1070.                     SA_DisplayID,    DisplayMode,
  1071.                     SA_Font,    &LocalUserFont,
  1072.                     SA_Behind,    TRUE,
  1073.                     SA_AutoScroll,    TRUE,
  1074.                     SA_Colors,    ColorSpec,
  1075.                 TAG_END))
  1076.                 {
  1077.                     if(BufferVisualInfo = GetVisualInfo(BufferScreen,TAG_DONE))
  1078.                     {
  1079.                         LocalizeMenu(BufferMenu,MSG_TERMBUFFER_PROJECT_MEN);
  1080.  
  1081.                         if(BufferMenuStrip = CreateMenus(BufferMenu,TAG_DONE))
  1082.                         {
  1083.                             if(LayoutMenus(BufferMenuStrip,BufferVisualInfo,
  1084.                                 GTMN_TextAttr,        &LocalUserFont,
  1085.                                 GTMN_NewLookMenus,    TRUE,
  1086.                             TAG_DONE))
  1087.                             {
  1088.                                 WORD TitleOffset,Len;
  1089.  
  1090.                                 Height = (BufferScreen -> Height - (BufferScreen -> BarHeight + 2)) / LocalTextFontHeight;
  1091.  
  1092.                                 Len = strlen(LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT));
  1093.  
  1094.                                 TitleOffset = TextLength(BufferScreen -> BarLayer -> rp,LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),Len) + TextLength(BufferScreen -> BarLayer -> rp," ",1) + 4;
  1095.  
  1096.                                     /* Open a cute window on our buffer screen. */
  1097.  
  1098.                                 if(BufferWindow = OpenWindowTags(NULL,
  1099.                                     WA_Top,        BufferScreen -> BarHeight + 2,
  1100.                                     WA_Left,    0,
  1101.                                     WA_Width,    BufferScreen -> Width,
  1102.                                     WA_Height,    Height * LocalTextFontHeight,
  1103.                                     WA_Backdrop,    TRUE,
  1104.                                     WA_Borderless,    TRUE,
  1105.                                     WA_SmartRefresh,FALSE,
  1106.                                     WA_CustomScreen,BufferScreen,
  1107.                                     WA_RMBTrap,    TRUE,
  1108.                                     WA_NewLookMenus,TRUE,
  1109.                                     WA_RptQueue,    1,
  1110.                                     WA_IDCMP,    IDCMP_IDCMPUPDATE | IDCMP_RAWKEY | IDCMP_INACTIVEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP_MENUPICK | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE,
  1111.                                 TAG_DONE))
  1112.                                 {
  1113.                                     if(BufferLineWidths = (UWORD *)AllocVec(2 * sizeof(UWORD) * (BufferWindow -> Height / LocalTextFontHeight + 1) + sizeof(UWORD) * (BufferWindow -> Width / LocalTextFontWidth + 1),MEMF_ANY | MEMF_CLEAR))
  1114.                                     {
  1115.                                         UWORD    Index;
  1116.                                         WORD    i;
  1117.  
  1118.                                         BufferLineOffsets    = &BufferLineWidths[BufferWindow -> Height / LocalTextFontHeight + 1];
  1119.                                         BufferColumnOffsets    = &BufferLineOffsets[BufferWindow -> Height / LocalTextFontHeight + 1];
  1120.  
  1121.                                         for(i = Index = 0 ; i < BufferWindow -> Height / LocalTextFontHeight + 1 ; i++)
  1122.                                         {
  1123.                                             BufferLineOffsets[i] = Index;
  1124.  
  1125.                                             Index += LocalTextFontHeight;
  1126.                                         }
  1127.  
  1128.                                         for(i = Index = 0 ; i < BufferWindow -> Width / LocalTextFontWidth + 1 ; i++)
  1129.                                         {
  1130.                                             BufferColumnOffsets[i] = Index;
  1131.  
  1132.                                             Index += LocalTextFontWidth;
  1133.                                         }
  1134.  
  1135.                                         if(CreateScroller(BufferWindow -> Height))
  1136.                                         {
  1137.                                                 /* Signal our father process that
  1138.                                                  * we're running.
  1139.                                                  */
  1140.  
  1141.                                             ReplyMsg(StartupMessage);
  1142.  
  1143.                                             StartupMessage = NULL;
  1144.  
  1145.                                             SetMenuStrip(BufferWindow,BufferMenuStrip);
  1146.  
  1147.                                             AddGList(BufferWindow,Scroller,(UWORD)-1,(UWORD)-1,NULL);
  1148.                                             RefreshGList(Scroller,BufferWindow,NULL,(UWORD)-1);
  1149.  
  1150.                                                 /* Determine maximum dimensions of
  1151.                                                  * the buffer screen (in rows and
  1152.                                                  * columns).
  1153.                                                  */
  1154.  
  1155.                                             NumBufferColumns    = (BufferWindow -> Width - (ARROW_WIDTH + 1)) / LocalTextFontWidth;
  1156.                                             NumBufferLines        = BufferWindow -> Height / LocalTextFontHeight;
  1157.  
  1158.                                             if(TopLine == -1 || !Config -> CaptureConfig -> RememberBufferScreen)
  1159.                                             {
  1160.                                                 switch(Config -> CaptureConfig -> OpenBufferScreen)
  1161.                                                 {
  1162.                                                     case BUFFER_TOP:
  1163.  
  1164.                                                         TopLine = 0;
  1165.                                                         break;
  1166.  
  1167.                                                     case BUFFER_END:
  1168.  
  1169.                                                         if((TopLine = Lines - NumBufferLines) < 0)
  1170.                                                             TopLine = 0;
  1171.  
  1172.                                                         break;
  1173.  
  1174.                                                     default:
  1175.  
  1176.                                                         TopLine = 0;
  1177.                                                         break;
  1178.                                                 }
  1179.                                             }
  1180.  
  1181.                                             if(TopLine > Lines - NumBufferLines)
  1182.                                                 TopLine = 0;
  1183.  
  1184. Restart:                                        BPort = BufferWindow -> RPort;
  1185.  
  1186.                                             SetFont(BPort,LocalFont);
  1187.  
  1188.                                                 /* Bring the screen to the front. */
  1189.  
  1190.                                             BumpWindow(BufferWindow);
  1191.  
  1192.                                                 /* Set the drawing pens for the window. */
  1193.  
  1194.                                             SetAPen(BPort,1);
  1195.                                             SetBPen(BPort,0);
  1196.                                             SetDrMd(BPort,JAM2);
  1197.  
  1198.                                                 /* Initial creation of the buffer display. */
  1199.  
  1200.                                             DisplayedLines = RedrawScreen(TopLine);
  1201.  
  1202.                                             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1203.                                                 PGA_Top,    TopLine,
  1204.                                                 PGA_Total,    Lines,
  1205.                                                 PGA_Visible,    NumBufferLines,
  1206.                                             TAG_DONE);
  1207.  
  1208.                                             BufferWindow -> Flags &= ~WFLG_RMBTRAP;
  1209.  
  1210.                                             do
  1211.                                             {
  1212.                                                     /* Show where we are. */
  1213.  
  1214.                                                 if(Lines)
  1215.                                                 {
  1216.                                                     LONG Width;
  1217.  
  1218.                                                     SetAPen(BufferScreen -> BarLayer -> rp,0);
  1219.                                                     SetBPen(BufferScreen -> BarLayer -> rp,1);
  1220.                                                     SetDrMd(BufferScreen -> BarLayer -> rp,JAM2);
  1221.  
  1222.                                                     if(LocaleBase)
  1223.                                                         SPrintf(PercentBuffer,"%lD/%lD (%ld%%)",TopLine,Lines > NumBufferLines ? Lines - NumBufferLines : 0,(100 * (TopLine + DisplayedLines)) / Lines);
  1224.                                                     else
  1225.                                                         SPrintf(PercentBuffer,"%ld/%ld (%ld%%)",TopLine,Lines > NumBufferLines ? Lines - NumBufferLines : 0,(100 * (TopLine + DisplayedLines)) / Lines);
  1226.  
  1227.                                                     Len = strlen(PercentBuffer);
  1228.  
  1229.                                                     Move(BufferScreen -> BarLayer -> rp,TitleOffset,BufferScreen -> BarLayer -> rp -> Font -> tf_Baseline + 1);
  1230.                                                     Text(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);
  1231.  
  1232.                                                     Width = TextLength(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);
  1233.  
  1234.                                                     if(LastWidth > Width)
  1235.                                                     {
  1236.                                                         SetAPen(BufferScreen -> BarLayer -> rp,1);
  1237.  
  1238.                                                         RectFill(BufferScreen -> BarLayer -> rp,TitleOffset + Width,1,TitleOffset + LastWidth - 1,BufferScreen -> BarLayer -> rp -> Font -> tf_YSize);
  1239.                                                     }
  1240.  
  1241.                                                     LastWidth = Width;
  1242.                                                 }
  1243.  
  1244.                                                 SignalSet = Wait(SIG_KILL | SIG_TOFRONT | SIG_UPDATE | SIG_MOVEUP | PORTMASK(BufferWindow -> UserPort));
  1245.  
  1246.                                                     /* Leave the town? */
  1247.  
  1248.                                                 if(SignalSet & SIG_KILL)
  1249.                                                     BufferTerminated = TRUE;
  1250.  
  1251.                                                     /* Bring our window to the front. */
  1252.  
  1253.                                                 if(SignalSet & SIG_TOFRONT)
  1254.                                                     BumpWindow(BufferWindow);
  1255.  
  1256.                                                     /* We've got one more line in the
  1257.                                                      * buffer.
  1258.                                                      */
  1259.  
  1260.                                                 if(SignalSet & SIG_UPDATE)
  1261.                                                 {
  1262.                                                     if(BufferLines && Lines)
  1263.                                                     {
  1264.                                                         if(Lines - TopLine > DisplayedLines && DisplayedLines < NumBufferLines)
  1265.                                                         {
  1266.                                                             LONG i = TopLine + DisplayedLines;
  1267.  
  1268.                                                             do
  1269.                                                                 PrintLine(BufferLines[i++],DisplayedLines++);
  1270.                                                             while(DisplayedLines < NumBufferLines && i < Lines);
  1271.                                                         }
  1272.                                                     }
  1273.  
  1274.                                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1275.                                                         PGA_Total,    Lines,
  1276.                                                         PGA_Visible,    DisplayedLines,
  1277.                                                     TAG_DONE);
  1278.  
  1279.                                                     Signal(ThisProcess,SIG_HANDSHAKE);
  1280.                                                 }
  1281.  
  1282.                                                     /* The contents of the buffer have moved
  1283.                                                      * up a line.
  1284.                                                      */
  1285.  
  1286.                                                 if(SignalSet & SIG_MOVEUP)
  1287.                                                 {
  1288.                                                     if(TopLine > 0)
  1289.                                                     {
  1290.                                                         LastTopLine = --TopLine;
  1291.  
  1292.                                                         SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1293.                                                             PGA_Top,TopLine,
  1294.                                                         TAG_DONE);
  1295.                                                     }
  1296.                                                     else
  1297.                                                     {
  1298.                                                         LONG i;
  1299.  
  1300.                                                         MarkArea(-1,-1,-1);
  1301.  
  1302.                                                         for(i = 0 ; i < NumBufferLines - 1 ; i++)
  1303.                                                             BufferLineWidths[i] = BufferLineWidths[i + 1];
  1304.  
  1305.                                                         ClipBlit(BPort,0,BufferLineOffsets[1],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  1306.  
  1307.                                                         PrintLine(BufferLines[NumBufferLines - 1],NumBufferLines - 1);
  1308.                                                     }
  1309.  
  1310.                                                     Signal(ThisProcess,SIG_HANDSHAKE);
  1311.                                                 }
  1312.  
  1313.                                                     /* Process the incoming window
  1314.                                                      * input.
  1315.                                                      */
  1316.  
  1317.                                                 while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
  1318.                                                 {
  1319.                                                     IClass        = Massage -> Class;
  1320.                                                     Code        = Massage -> Code;
  1321.                                                     Qualifier    = Massage -> Qualifier;
  1322.                                                     MouseX        = Massage -> MouseX;
  1323.                                                     MouseY        = Massage -> MouseY;
  1324.                                                     TagList        = (struct TagItem *)Massage -> IAddress;
  1325.  
  1326.                                                         /* This hack is necessary to obtain the
  1327.                                                          * character codes generated for the cursor
  1328.                                                          * keys. A control or alternate qualifier
  1329.                                                          * would spoil the result (i.e. we would
  1330.                                                          * not get a valid key code).
  1331.                                                          */
  1332.  
  1333.                                                     Massage -> Qualifier = NULL;
  1334.  
  1335.                                                     Char = KeyConvert(Massage,NULL,NULL);
  1336.  
  1337.                                                         /* Just in case anybody needs it... */
  1338.  
  1339.                                                     Massage -> Qualifier = Qualifier;
  1340.  
  1341.                                                     ReplyMsg((struct Message *)Massage);
  1342.  
  1343.                                                     if(IClass == IDCMP_IDCMPUPDATE)
  1344.                                                     {
  1345.                                                         switch(GetTagData(GA_ID,0,TagList))
  1346.                                                         {
  1347.                                                             case GAD_UP:
  1348.  
  1349.                                                                 if(TopLine > 0)
  1350.                                                                 {
  1351.                                                                     TopLine--;
  1352.  
  1353.                                                                     MarkArea(-1,-1,-1);
  1354.  
  1355.                                                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1356.                                                                         PGA_Top,TopLine,
  1357.                                                                     TAG_DONE);
  1358.  
  1359.                                                                     DisplayedLines = RedrawScreen(TopLine);
  1360.                                                                 }
  1361.  
  1362.                                                                 break;
  1363.  
  1364.                                                             case GAD_DOWN:
  1365.  
  1366.                                                                 if(TopLine + NumBufferLines < Lines)
  1367.                                                                 {
  1368.                                                                     TopLine++;
  1369.  
  1370.                                                                     MarkArea(-1,-1,-1);
  1371.  
  1372.                                                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1373.                                                                         PGA_Top,TopLine,
  1374.                                                                     TAG_DONE);
  1375.  
  1376.                                                                     DisplayedLines = RedrawScreen(TopLine);
  1377.                                                                 }
  1378.  
  1379.                                                                 break;
  1380.                                                         }
  1381.                                                     }
  1382.  
  1383.                                                     if(IClass == IDCMP_MOUSEMOVE || IClass == IDCMP_GADGETDOWN || IClass == IDCMP_GADGETUP)
  1384.                                                     {
  1385.                                                         LONG Position;
  1386.  
  1387.                                                         GetAttr(PGA_Top,Scroller,&Position);
  1388.  
  1389.                                                         if(Position != TopLine)
  1390.                                                         {
  1391.                                                             MarkArea(-1,-1,-1);
  1392.  
  1393.                                                             DisplayedLines = RedrawScreen(TopLine = Position);
  1394.                                                         }
  1395.                                                     }
  1396.  
  1397.                                                     if(IClass == IDCMP_RAWKEY)
  1398.                                                     {
  1399.                                                         if(Code == HELP_CODE)
  1400.                                                             GuideDisplay(CONTEXT_TEXTBUFFER);
  1401.  
  1402.                                                         if(LastChar)
  1403.                                                         {
  1404.                                                             if((Code & IECODE_UP_PREFIX) || !(LastQualifier & IEQUALIFIER_REPEAT))
  1405.                                                             {
  1406.                                                                 SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1407.                                                                     PGA_Top,TopLine,
  1408.                                                                 TAG_DONE);
  1409.                                                             }
  1410.                                                         }
  1411.  
  1412.                                                         if(LastChar = Char)
  1413.                                                         {
  1414.                                                                 /* Use the numeric keypad keys to
  1415.                                                                  * move through the buffer.
  1416.                                                                  */
  1417.  
  1418.                                                             if(Qualifier & IEQUALIFIER_NUMERICPAD)
  1419.                                                             {
  1420.                                                                     /* Remove the numpad qualifier. */
  1421.  
  1422.                                                                 Qualifier &= ~IEQUALIFIER_NUMERICPAD;
  1423.  
  1424.                                                                 switch(Char - '0')
  1425.                                                                 {
  1426.                                                                         /* Jump to bottom. */
  1427.  
  1428.                                                                     case 1: Char = CDN;
  1429.                                                                         Qualifier |= IEQUALIFIER_CONTROL;
  1430.                                                                         break;
  1431.  
  1432.                                                                         /* Jump to top. */
  1433.  
  1434.                                                                     case 7: Char = CUP;
  1435.                                                                         Qualifier |= IEQUALIFIER_CONTROL;
  1436.                                                                         break;
  1437.  
  1438.                                                                         /* Move one page down. */
  1439.  
  1440.                                                                     case 3: Char = CDN;
  1441.                                                                         Qualifier |= IEQUALIFIER_LSHIFT;
  1442.                                                                         break;
  1443.  
  1444.                                                                         /* Move one page up. */
  1445.  
  1446.                                                                     case 9: Char = CUP;
  1447.                                                                         Qualifier |= IEQUALIFIER_LSHIFT;
  1448.                                                                         break;
  1449.  
  1450.                                                                         /* Move one line down. */
  1451.  
  1452.                                                                     case 2: Char = CDN;
  1453.                                                                         break;
  1454.  
  1455.                                                                         /* Move one line up. */
  1456.  
  1457.                                                                     case 8: Char = CUP;
  1458.                                                                         break;
  1459.                                                                 }
  1460.                                                             }
  1461.  
  1462.                                                                 /* Check cursor keys. */
  1463.  
  1464.                                                             switch(Char)
  1465.                                                             {
  1466.                                                                     /* Scroll the buffer up. */
  1467.  
  1468.                                                                 case CUP:
  1469.  
  1470.                                                                     if(Qualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT))
  1471.                                                                     {
  1472.                                                                         MarkArea(-1,-1,-1);
  1473.  
  1474.                                                                         if(TopLine)
  1475.                                                                         {
  1476.                                                                             DisplayedLines = RedrawScreen(TopLine = 0);
  1477.  
  1478.                                                                             LastChar = 0;
  1479.  
  1480.                                                                             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1481.                                                                                 PGA_Top,TopLine,
  1482.                                                                             TAG_DONE);
  1483.                                                                         }
  1484.  
  1485.                                                                         break;
  1486.                                                                     }
  1487.  
  1488.                                                                     if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1489.                                                                     {
  1490.                                                                         LONG NewCurrentLine;
  1491.  
  1492.                                                                         if((NewCurrentLine = TopLine - NumBufferLines) < 0)
  1493.                                                                             NewCurrentLine = 0;
  1494.  
  1495.                                                                         MarkArea(-1,-1,-1);
  1496.  
  1497.                                                                         if(NewCurrentLine != TopLine)
  1498.                                                                         {
  1499.                                                                             DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  1500.  
  1501.                                                                             LastChar = 0;
  1502.  
  1503.                                                                             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1504.                                                                                 PGA_Top,TopLine,
  1505.                                                                             TAG_DONE);
  1506.                                                                         }
  1507.  
  1508.                                                                         break;
  1509.                                                                     }
  1510.  
  1511.                                                                     if(TopLine)
  1512.                                                                     {
  1513.                                                                         MarkArea(-1,-1,-1);
  1514.  
  1515.                                                                         DisplayedLines = RedrawScreen(--TopLine);
  1516.                                                                     }
  1517.  
  1518.                                                                     break;
  1519.  
  1520.                                                                     /* Scroll the buffer down. */
  1521.  
  1522.                                                                 case CDN:
  1523.  
  1524.                                                                     if(Qualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT))
  1525.                                                                     {
  1526.                                                                         LONG NewCurrentLine;
  1527.  
  1528.                                                                         if((NewCurrentLine = Lines - NumBufferLines) < 0)
  1529.                                                                             NewCurrentLine = 0;
  1530.  
  1531.                                                                         MarkArea(-1,-1,-1);
  1532.  
  1533.                                                                         if(TopLine != NewCurrentLine)
  1534.                                                                         {
  1535.                                                                             DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  1536.  
  1537.                                                                             LastChar = 0;
  1538.  
  1539.                                                                             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1540.                                                                                 PGA_Top,TopLine,
  1541.                                                                             TAG_DONE);
  1542.                                                                         }
  1543.  
  1544.                                                                         break;
  1545.                                                                     }
  1546.  
  1547.                                                                     if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1548.                                                                     {
  1549.                                                                         LONG NewCurrentLine;
  1550.  
  1551.                                                                         if((NewCurrentLine = TopLine + (2 * NumBufferLines)) > Lines)
  1552.                                                                             NewCurrentLine = Lines;
  1553.  
  1554.                                                                         if((NewCurrentLine = NewCurrentLine - NumBufferLines) < 0)
  1555.                                                                             NewCurrentLine = 0;
  1556.  
  1557.                                                                         MarkArea(-1,-1,-1);
  1558.  
  1559.                                                                         if(NewCurrentLine != TopLine)
  1560.                                                                         {
  1561.                                                                             DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  1562.  
  1563.                                                                             LastChar = 0;
  1564.  
  1565.                                                                             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1566.                                                                                 PGA_Top,TopLine,
  1567.                                                                             TAG_DONE);
  1568.                                                                         }
  1569.  
  1570.                                                                         break;
  1571.                                                                     }
  1572.  
  1573.                                                                     if(TopLine + NumBufferLines < Lines)
  1574.                                                                     {
  1575.                                                                         MarkArea(-1,-1,-1);
  1576.  
  1577.                                                                         DisplayedLines = RedrawScreen(++TopLine);
  1578.                                                                     }
  1579.  
  1580.                                                                     break;
  1581.                                                             }
  1582.  
  1583.                                                             LastQualifier = Qualifier;
  1584.                                                         }
  1585.                                                         else
  1586.                                                             LastQualifier = NULL;
  1587.  
  1588.                                                         continue;
  1589.                                                     }
  1590.  
  1591.                                                         /* User hit a mouse button. */
  1592.  
  1593.                                                     if(IClass == IDCMP_MOUSEBUTTONS && !(Code & IECODE_UP_PREFIX))
  1594.                                                     {
  1595.                                                         MarkArea(-1,-1,-1);
  1596.  
  1597.                                                             /* Reasonable dimensions? */
  1598.  
  1599.                                                         if(MouseY / LocalTextFontHeight < DisplayedLines && MouseX / LocalTextFontWidth < NumBufferColumns)
  1600.                                                         {
  1601.                                                             ObtainSemaphore(BufferSemaphore);
  1602.  
  1603.                                                             BufferClip();
  1604.  
  1605.                                                             LastTopLine = TopLine;
  1606.  
  1607.                                                             ReleaseSemaphore(BufferSemaphore);
  1608.  
  1609.                                                             if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1610.                                                                 Signal(ThisProcess,SIG_CLIP);
  1611.  
  1612.                                                             break;
  1613.                                                         }
  1614.                                                     }
  1615.  
  1616.                                                     if(IClass == IDCMP_MENUPICK)
  1617.                                                     {
  1618.                                                         struct MenuItem *MenuItem;
  1619.  
  1620.                                                         while(Code != MENUNULL)
  1621.                                                         {
  1622.                                                             MenuItem = ItemAddress(BufferMenuStrip,Code);
  1623.  
  1624.                                                             switch((ULONG)GTMENUITEM_USERDATA(MenuItem))
  1625.                                                             {
  1626.                                                                 case MEN_SEARCH:
  1627.  
  1628.                                                                     StartBufferSearch(TRUE);
  1629.                                                                     break;
  1630.  
  1631.                                                                 case MEN_REPEAT:
  1632.  
  1633.                                                                     StartBufferSearch(FALSE);
  1634.                                                                     break;
  1635.  
  1636.                                                                 case MEN_GOTO:
  1637.  
  1638.                                                                     if(Window)
  1639.                                                                         BumpWindow(Window);
  1640.  
  1641.                                                                     break;
  1642.  
  1643.                                                                 case MEN_QUITBUF:
  1644.  
  1645.                                                                     BufferTerminated = TRUE;
  1646.                                                                     break;
  1647.  
  1648.                                                                 case MEN_CLEARBUF_CONTENTS:
  1649.  
  1650.                                                                     if(Lines)
  1651.                                                                     {
  1652.                                                                         BlockWindows();
  1653.  
  1654.                                                                         BlockWindow(BufferWindow);
  1655.  
  1656.                                                                         if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1657.                                                                         {
  1658.                                                                             FreeBuffer();
  1659.  
  1660.                                                                             ReleaseWindow(BufferWindow);
  1661.  
  1662.                                                                             ReleaseWindows();
  1663.  
  1664.                                                                             FlushMsg(BufferWindow);
  1665.  
  1666.                                                                             TopLine = 0;
  1667.  
  1668.                                                                             goto Restart;
  1669.                                                                         }
  1670.                                                                         else
  1671.                                                                         {
  1672.                                                                             if(MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_BUFFER_STILL_HOLDS_LINES_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT),Lines))
  1673.                                                                             {
  1674.                                                                                 FreeBuffer();
  1675.  
  1676.                                                                                 ReleaseWindow(BufferWindow);
  1677.  
  1678.                                                                                 ReleaseWindows();
  1679.  
  1680.                                                                                 FlushMsg(BufferWindow);
  1681.  
  1682.                                                                                 TopLine = 0;
  1683.  
  1684.                                                                                 goto Restart;
  1685.                                                                             }
  1686.                                                                         }
  1687.  
  1688.                                                                         ReleaseWindow(BufferWindow);
  1689.  
  1690.                                                                         ReleaseWindows();
  1691.  
  1692.                                                                         FlushMsg(BufferWindow);
  1693.                                                                     }
  1694.  
  1695.                                                                     break;
  1696.                                                             }
  1697.  
  1698.                                                             Code = MenuItem -> NextSelect;
  1699.                                                         }
  1700.                                                     }
  1701.  
  1702.                                                 }
  1703.                                             }
  1704.                                             while(!BufferTerminated);
  1705.  
  1706.                                             RemoveGList(BufferWindow,Scroller,(UWORD)-1);
  1707.  
  1708.                                             DeleteScroller();
  1709.                                         }
  1710.  
  1711.                                         FreeVec(BufferLineWidths);
  1712.                                     }
  1713.  
  1714.                                     if(Window)
  1715.                                         BumpWindow(Window);
  1716.  
  1717.                                     MarkArea(-1,-1,-1);
  1718.  
  1719.                                     ScreenToBack(BufferScreen);
  1720.  
  1721.                                     BufferWindow -> Flags |= WFLG_RMBTRAP;
  1722.  
  1723.                                     ClearMenuStrip(BufferWindow);
  1724.  
  1725.                                     CloseWindow(BufferWindow);
  1726.                                 }
  1727.                             }
  1728.  
  1729.                             FreeMenus(BufferMenuStrip);
  1730.                         }
  1731.  
  1732.                         FreeVisualInfo(BufferVisualInfo);
  1733.                     }
  1734.  
  1735.                     CloseScreen(BufferScreen);
  1736.                 }
  1737.             }
  1738.  
  1739.             CloseFont(LocalFont);
  1740.         }
  1741.     }
  1742.  
  1743.         /* Release the search buffer data. */
  1744.  
  1745.     if(BufferSearchInfo)
  1746.     {
  1747.         DeleteSearchInfo(BufferSearchInfo);
  1748.  
  1749.         BufferSearchInfo = NULL;
  1750.     }
  1751.  
  1752.     Forbid();
  1753.  
  1754.     BufferProcess = NULL;
  1755.  
  1756.     if(StartupMessage)
  1757.         ReplyMsg(StartupMessage);
  1758.     else
  1759.         Signal(ThisProcess,SIG_HANDSHAKE);
  1760. }
  1761.